package com.jeesite.modules.fl.web.weixin;

import com.jeesite.common.network.IpUtils;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.config.web.WeixinProperties;
import com.jeesite.modules.fl.entity.Leaguer;
import com.jeesite.modules.fl.service.LeaguerService;
import com.jeesite.modules.fl.utils.FlConstants;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.utils.UserUtils;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import javax.servlet.http.HttpServletRequest;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@ConditionalOnBean(WxMpService.class)
@RequestMapping("/wx")
public class WeixinController {
  private Logger log = LoggerFactory.getLogger(WeixinController.class);

  @Autowired
  private WxMpService wxService;

  @Autowired
  private UserService userService;

  @Autowired
  private WeixinProperties weixinProperties;

  @Autowired
  private LeaguerService leaguerService;
  
  private static Map<String, String> urlMap = new HashMap<>();

  static {
    urlMap.put("appointment", "appointment.html");
    urlMap.put("about", "about.html");
    urlMap.put("clinic", "list.html?type=1");
    urlMap.put("activity", "list.html?type=2");

    urlMap.put("center", "center.html");
    urlMap.put("myappointment", "center_2.html");
    urlMap.put("myremark", "center_1.html");
    urlMap.put("enterprise", "list.html?type=3");
  }


  /**
   * 供 微信平台调用以确认服务有效性
   */
  @RequestMapping("/portal/verify")
  @ResponseBody
  public String verify(@RequestParam(name = "signature", required = false) String signature,
                        @RequestParam(name = "timestamp", required = false) String timestamp,
                        @RequestParam(name = "nonce", required = false) String nonce,
                        @RequestParam(name = "echostr", required = false) String echostr) {

    log.info("\n接收到来自微信服务器的认证消息：[{}, {}, {}, {}]", signature,
        timestamp, nonce, echostr);
    if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
      throw new IllegalArgumentException("请求参数非法，请核实!");
    }

    if (wxService.checkSignature(timestamp, nonce, signature)) {
      return echostr;
    }

    return "非法请求";
  }

  @RequestMapping("/entry/{module}")
  public ModelAndView entry(
      @PathVariable("module")String module,
      @RequestParam(value = "bind",defaultValue = "true")boolean needBindFlag,
      HttpServletRequest request) {
    Subject subject = SecurityUtils.getSubject();
    Session session = subject.getSession();
    if (session.getAttribute(FlConstants.SESS_OPEN_ID) == null) {
      log.debug("no open id in session redirect to oauth");
      String url = wxService.oauth2buildAuthorizationUrl(weixinProperties.getRedirectUrl()
              +"?module="+module+"&bind="+needBindFlag,
          WxConsts.OAuth2Scope.SNSAPI_BASE, null);
      return new ModelAndView(new RedirectView(url));
    }

    if (subject.isAuthenticated()) {
      log.debug("current user is {}", subject.getPrincipal());
      return makeSetSessionView(module, session, true);
    }

    User searchVo = new User();
    searchVo.setWxOpenid(session.getAttribute(FlConstants.SESS_OPEN_ID).toString());
    List<User> users = userService.findList(searchVo);
    if (users == null || users.size() < 1) {
      if (needBindFlag) {
        return makeRegisterMav();
      } else {
        //return makeSetSessionView(module, session, false);
        return makeSetSessionView(module, session, weixinProperties.getRegisterUrl(), false);
      }
    }
    User user = users.get(0);
    Leaguer leaguer = leaguerService.get(user.getRefCode());
    String lang = request.getParameter("lang");
    leaguer.setLanguage(lang);
    leaguerService.save(leaguer);
    WeixinToken loginToken = new WeixinToken(user.getLoginCode(), user.getPassword(), false,
        IpUtils.getRemoteAddr(request), "captcha", ServletUtils.getExtParams(request)
    );
    subject.login(loginToken);
    ModelAndView mav = makeSetSessionView(module, session, true);
    return mav;
  }

  private ModelAndView makeSetSessionView(String module, Session session, boolean boundFlag) {
    ModelAndView mav = new ModelAndView("modules/fl/setsession");
    mav.addObject("sessionid", session.getId());
    mav.addObject("targetUrl", makeToUrl(module));
    mav.addObject("bindFlag", boundFlag);
    return mav;
  }

  private ModelAndView makeSetSessionView(String module, Session session, String url, boolean boundFlag) {
    ModelAndView mav = new ModelAndView("modules/fl/setsession");
    mav.addObject("sessionid", session.getId());
    mav.addObject("targetUrl", url);
    mav.addObject("bindFlag", boundFlag);
    return mav;
  }

  private String makeToUrl(String module) {
    String path = null;
    Map<String, String> entries = weixinProperties.getEntries();
    if (entries != null && entries.containsKey(module)) {
      path = entries.get(module);
    }
    if (StringUtils.isBlank(path)) {
      path = urlMap.get(module);
    }
    if (StringUtils.isBlank(path)) {
      path = urlMap.get("center");
    }
    return weixinProperties.getBaseUrl() + path;
  }

  private ModelAndView makeRegisterMav() {
    return new ModelAndView(new RedirectView(weixinProperties.getRegisterUrl()));
  }

  /**
   * 微信redirect 回来的接口， 在这里获取 open id 并做相应处理
   */
  @RequestMapping("/authback")
  public ModelAndView authBack(
      @RequestParam("code")String code,
      @RequestParam(value = "rurl",required = false)String returnUrl,
      @RequestParam(value= "module", required = false)String module,
      @RequestParam(value= "bind", defaultValue = "true")boolean needBindFlag,
      HttpServletRequest request
      ) {
    WxMpOAuth2AccessToken token;
    try {
      token = wxService.oauth2getAccessToken(code);
    } catch (WxErrorException e) {
//      e.printStackTrace();
      log.error("oauth2get token error", e);
      throw new RuntimeException("微信授权失败");
    }
    String openId = token.getOpenId();
    if (null == openId) {
      log.error("oauth2get openid error");
      throw new RuntimeException("微信授权失败，未获得openid");
    }
    log.debug("response open id is {}", openId);
    Session session = UserUtils.getSession();
    session.setAttribute(FlConstants.SESS_OPEN_ID, openId);
    // get user info by openId
    User searchVo = new User();
    searchVo.setWxOpenid(openId);
    List<User> users = userService.findList(searchVo);
    if (users == null || users.size() < 1) {
      if (needBindFlag) {
        return makeRegisterMav();
      } else {
        return makeSetSessionView(module, session, false);
      }
    }
    User user = users.get(0);
    WeixinToken loginToken = new WeixinToken(user.getLoginCode(), user.getPassword(), false,
        IpUtils.getRemoteAddr(request), "captcha", ServletUtils.getExtParams(request)
    );
    Subject subject = SecurityUtils.getSubject();
    subject.login(loginToken);
    log.debug("set open id into shiro session");
    subject.getSession().setAttribute(FlConstants.SESS_OPEN_ID, openId);

    ModelAndView mav;
    if (StringUtils.isNotBlank(returnUrl)) {
      mav = makeSetSessionView(module, session, returnUrl,true);
    } else {
      mav = makeSetSessionView(module, session, true);
    }
    return mav;
  }

  @RequestMapping("/logout")
  @ResponseBody
  public String  doLogout() {
    Subject subject = SecurityUtils.getSubject();
    Session session = subject.getSession();
    session.removeAttribute(FlConstants.SESS_OPEN_ID);
    subject.logout();
    return "logout";
  }

  @PostMapping("/testSendMessage")
  @ResponseBody
  public Object testSendMessage(
      @RequestParam("mobile")String mobile,
      @RequestParam("secret")String secret
      ) {
    if (!StringUtils.equals("test23423fasndfhsa", secret)) {
      return "NoRight";
    }
    User so = new User();
    so.setLoginCode(mobile);
    User user = userService.getByLoginCode(so);
    if (null != user && StringUtils.isNotEmpty(user.getWxOpenid())) {
      WxMpTemplateMessage message = WxMpTemplateMessage.builder()
          .toUser(user.getWxOpenid())
          .templateId("FrEFY_Pe9Lqh6QJ5X6nuHL6aSiftp9dF8bURloZEbgI")
          .url("")
          .build();
      message.addData(new WxMpTemplateData("first", "您好，富乐医疗已经为您预约成功。","#FF33FF"));
      message.addData(new WxMpTemplateData("patientName", "张山","#FF00FF"));
      message.addData(new WxMpTemplateData("patientSex", "男","#FF00FF"));
      message.addData(new WxMpTemplateData("hospitalName", "华山医院","#FF00FF"));
      message.addData(new WxMpTemplateData("department", "外科","#FF00FF"));
      message.addData(new WxMpTemplateData("doctor", "凌然医生","#FF00FF"));
      message.addData(new WxMpTemplateData("seq", "123123","#FF00FF"));
      message.addData(new WxMpTemplateData("remark", "取号时间：2013年10月10日 10:25\n" +
          "请您准时到达取号","#FF00FF"));

      try {
        wxService.getTemplateMsgService().sendTemplateMsg(message);
      } catch (WxErrorException e) {
        log.error("failed send WEIXIN template message ", e);
        return "Failed to send message with error: " + e.getMessage();
      }
      return "success";
    }
    return "no user";
  }
}
